<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js面向对象</title>
</head>
<body>

<br>
<p>声明：bojiangzhou的博客，感谢。</p>
<p>摘录地址：https://www.cnblogs.com/chiangchou/p/js-oop1.html </p>
</body>
<script>
    //方式一  通过Object创建
    //弊端：这种方式有一个非常大的弊端，就是如果我有多个人怎么办，每次都要新建一个对象，然后添加属性、方法，这种方式是一次性的，会产生大量重复代码，这是不可取的。
    /**
     * 创建一个新对象
     * new Object()创建出来的对象几乎是空白的，需要自己添加属性，方法
     */
    var person = new Object();
    //为person对象添加属性
    person.name = "jiangzhou";
    person.age = 22;
    //为person对象添加方法
    person.showName = function () {
        alert("姓名：" + this.name);
    }
    person.showAge = function () {
        alert("年龄：" + this.age);
    }
    //调用对象的方法
    person.showName();
    person.showAge();
    //方式二  工厂模式
    //弊端：
    //1、一般我们创建对象是通过new来创建，比如new Date()，这里使用的是方法创建。使用new来创建可以简化一些代码，也带来一些新的特性。
    //2、每个对象都有一套自己的方法，浪费资源(虽然对于现在的计算机来说不算什么，但我们尽量将设计做到最好就行了)。
    //这里为什么说每个对象都有自己的一套方法呢，是因为创建function()的时候其本质是通过new Function()来创建的，会诞生一个新的函数对象，所以每个对象的方法是不一样的，这样就存在资源浪费的问题了。查看"看这里"以下代码
    //构造函数：工厂
    function createPerson(name, age) {
        var person = new Object();

        //原料
        person.name = name;
        person.age = age;

        //加工
        person.showName = function () {
            alert("姓名：" + this.name);
        }
        person.showAge = function () {
            alert("年龄：" + this.age);
        }
        /**
         * 看这里
         *  person.showSex = function(){} 等价于 person.showSex = new Function('');
         *  也就是说我们在创建这个函数的时候就是新建了一个对象。
         */
        person.showSex = new Function('alert("性别："+this.sex)');
        //出厂
        return person;
    }

    //创建两个对象
    var p1 = createPerson("jiangzhou", 22);
    var p2 = createPerson("tom", 20);

    //调用对象方法
    p1.showName();
    p1.showAge();

    p2.showName();
    p2.showAge();
    //看这里
    alert(p1.showName == p2.showName); //false
    //方式三 使用new 来创建JS对象
    //这种方式只解决了方式二的第一个问题，每个对象还是有自己的一套方法，具体看“看这里”
    function Person(name, age) {
        /**
         * 可以假想成系统会创建一个对象
         * var this = new Object();
         */

        alert(this); //弹出Object

        this.name = name;
        this.age = age;

        this.showName = function () {
            alert("姓名：" + this.name);
        }
        this.showAge = function () {
            alert("年龄：" + this.age);
        }

        /**
         * 假想返回了对象
         * return this;
         */
    }

    //创建两个对象
    var p1 = new Person("jiangzhou", 22);//可以看到在外面new了在function里面就不用new了；在function里面new了，在外面就不用new了；O(∩_∩)O~
    var p2 = new Person("Lyli", 20);
    //看这里
    alert(p1.showName == p2.showName); //false
    //方式四 在function原型(prototype)上进行扩展
    /**
     * Person构造函数：在JS中，构造函数其实就可以看成类，对某个对象的抽象定义。
     * @param {Object} name
     * @param {Object} age
     */
    function Person(name, age) {
        //属性：每个对象的属性各不相同
        this.name = name;
        this.age = age;
    }

    //在原型上添加方法，这样创建的所有对象都是用的同一套方法
    Person.prototype.showName = function () {
        alert("姓名：" + this.name);
    }
    Person.prototype.showAge = function () {
        alert("年龄：" + this.age);
    }

    //创建两个对象
    var p1 = new Person("jiangzhou", 22);
    var p2 = new Person("Lyli", 20);

    alert(p1.showName == p2.showName); //true
    //这里为什么两个对象的方法是相等的呢，可以看成如下
    alert(p1.showName == Person.prototype.showName); //true

    //一个新的方法继承方式四中的Person
    function Children(name, age, major) {
        Person.call(this,name,age);
        this.major =major
    }
    for (var i in Person.prototype) {
        Children.prototype[i]=Person.prototype[i]
    }
    Children.prototype.showMajor=function(){
        alert(this.name+this.age+this.major)
    }
    var childr=new Children("你大爷","12岁","上学呢");
    childr.showMajor();
</script>
</html>